/* Filename  : iocontrol.c
 * 
 * Author    : Shang Wentao
 * Email     : wentaoshang@gmail.com
 * Date      : May 19, 2009
 * 
 * This file contains the handle function for
 * the driver ioctl calls. It is not part of 
 * the original Passthru NDIS driver. 
 *
 */

#include "precomp.h"
#pragma hdrstop
#include "iocommon.h"

NTSTATUS
DevIoControl(
    IN PDEVICE_OBJECT    pDeviceObject,
    IN PIRP              pIrp
    )
/*++

Routine Description:

    This is the dispatch routine for handling device ioctl requests.

Arguments:

    pDeviceObject - Pointer to the device object.

    pIrp - Pointer to the request packet.

Return Value:

    Status is returned.

--*/
{
    PIO_STACK_LOCATION  pIrpSp;
    NTSTATUS            NtStatus = STATUS_SUCCESS;
    ULONG               FunctionCode;
    ULONG               BytesReturned = 0;
    PUCHAR              ioBuffer = NULL;
    ULONG               inputBufferLength;
    ULONG               outputBufferLength;
    USHORT              temp;
    
    UNREFERENCED_PARAMETER(pDeviceObject);
    
    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    
    ioBuffer = pIrp->AssociatedIrp.SystemBuffer;
    inputBufferLength  = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
    outputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
    
    FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
    
    DBGPRINT(("==> DevIoControl: Context %p\n", (pIrpSp->FileObject)->FsContext ));
    
    switch (FunctionCode)
    {
        case IOCTL_PTUSERIO_SET_MOD:
            if( inputBufferLength != sizeof(Mod) ) {
                DBGPRINT(("==> ioctl: SET_MOD input type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(&temp, (PVOID)ioBuffer, inputBufferLength);
                if( temp > 4096 ) {
                    DBGPRINT(("==> ioctl: Mod input %d is too large!\n", temp));
                    NtStatus = STATUS_UNSUCCESSFUL;
                }
                else if( temp <= Res ) {
                    DBGPRINT(("==> ioctl: Mod input %d is smaller than Res!\n", temp));
                    NtStatus = STATUS_UNSUCCESSFUL;
                }
                else {
                    Mod = temp;
                    DBGPRINT(("==> ioctl: set Mod to %d\n", Mod));
                    free_list(&Head);
                    DBGPRINT(("==> Old Map List Freed!\n"));
                }
            }
            break;
            
        case IOCTL_PTUSERIO_GET_MOD:
            if( outputBufferLength != sizeof(Mod) ) {
                DBGPRINT(("==> ioctl: GET_MOD output type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(ioBuffer, &Mod, outputBufferLength);
                //*((PUSHORT)ioBuffer) = Mod;
                DBGPRINT(("==> ioctl: get Mod by user!\n"));
                BytesReturned = sizeof(Mod);
            }
            break;
            
        case IOCTL_PTUSERIO_SET_RES:
            if( inputBufferLength != sizeof(Res) ) {
                DBGPRINT(("==> ioctl: SET_RES input type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(&temp, (PVOID)ioBuffer, inputBufferLength);
                if( temp >= Mod ) {
                    DBGPRINT(("==> ioctl: Res input %d is too large!\n", temp));
                    NtStatus = STATUS_UNSUCCESSFUL;
                }
                else {
                    Res = temp;
                    DBGPRINT(("==> ioctl: set Res to %d\n", Res));
                    free_list(&Head);
                    DBGPRINT(("==> Old Map List Freed!\n"));
                }
            }
            break;
            
        case IOCTL_PTUSERIO_GET_RES:
            if( outputBufferLength != sizeof(Res) ) {
                DBGPRINT(("==> ioctl: GET_RES output type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(ioBuffer, &Res, outputBufferLength);
                //*((PUSHORT)ioBuffer) = Res;
                DBGPRINT(("==> ioctl: get Res by user!\n"));
                BytesReturned = sizeof(Res);
            }
            break;
            
        case IOCTL_PTUSERIO_SET_TIMEOUT:
            if( inputBufferLength != sizeof(TimeOut) ) {
                DBGPRINT(("==> ioctl: SET_TIMEOUT input type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(&TimeOut, (PVOID)ioBuffer, inputBufferLength);
                DBGPRINT(("==> ioctl: set TimeOut to : HighPart %ld  LowPart %ld\n", TimeOut.HighPart, TimeOut.LowPart));
            }
            break;
            
        case IOCTL_PTUSERIO_GET_TIMEOUT:
            if( outputBufferLength != sizeof(TimeOut) ) {
                DBGPRINT(("==> ioctl: GET_TIMEOUT output type invalid!\n"));
                NtStatus = STATUS_UNSUCCESSFUL;
            }
            else {
                NdisMoveMemory(ioBuffer, &TimeOut, outputBufferLength);
                //*((PUSHORT)ioBuffer) = TimeOut;
                DBGPRINT(("==> ioctl: get TimeOut by user!\n"));
                BytesReturned = sizeof(TimeOut);
            }
            break;
        
        case IOCTL_PTUSERIO_SET_AUTOCONFIG:
            AutoConfig = 1;
            DBGPRINT(("==> ioctl: autoconfig enabled by user!\n"));
            break;
            
        case IOCTL_PTUSERIO_UNSET_AUTOCONFIG:
            AutoConfig = 0;
            DBGPRINT(("==> ioctl: autoconfig disabled by user!\n"));
            Mod = 256;
            DBGPRINT(("==> ioctl: reset Mod to %d\n", Mod));
            Res = 1;
            DBGPRINT(("==> ioctl: reset Res to %d\n", Res));
            free_list(&Head);
            DBGPRINT(("==> Old Map List Freed!\n"));
            break;
            
        default:
            NtStatus = STATUS_NOT_SUPPORTED;
    }
    
    pIrp->IoStatus.Information = BytesReturned;
    
    DBGPRINT(("<== Leaving DevIoControl\n"));
    
    return NtStatus;
} 

